package com.panopset.game.card;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;

import com.panopset.compat.MathUtil;
import com.panopset.compat.Strings;
import com.panopset.compat.Util;

/**
 * Multiple deck shoe.
 *
 * @author Karl Dinwiddie
 *
 */
public class Shoe {

    private final Integer numberOfDecks;
    public Long numberOfShuffles = 0L;
    private List<Deck> decks;
    public int cut = 0;

    public Shoe(final Integer numberOfDecks) {
        this.numberOfDecks = numberOfDecks;
        shuffle();
        if (stackedDeckForTesting.size() < 1) {
            cut = MathUtil.random(10, 13 * numberOfDecks);
            for (int i = 0; i < cut; i++) {
                deal();
            }
        }
    }

    private static int deckColorSwitcher = 0;
    public static boolean isBlue() {
        return deckColorSwitcher == 0;
    }
    public void shuffle() {
        deckColorSwitcher = 1 - deckColorSwitcher;
        decks = new ArrayList<Deck>();
        numberOfShuffles++;
        for (int i = 0; i < numberOfDecks; i++) {
            decks.add(new Deck());
        }
    }

    public Card deal() {
        if (stackedDeckForTesting.size() > 0) {
            return stackedDeckForTesting.remove(0);
        }
        // if (remaining() < 1) {
        // throw new ArrayIndexOutOfBoundsException());
        // }
        int i = MathUtil.random(0, decks.size() - 1);
        Deck deck = decks.get(i);
        Card rtn = deck.deal();
        if (deck.remaining() < 1) {
            decks.remove(i);
        }
        return rtn;
    }

    public int remaining() {
        int rtn = 0;
        for (Deck deck : decks) {
            rtn += deck.remaining();
        }
        return rtn;
    }

    private static List<Card> stackedDeckForTesting = new ArrayList<Card>();
    {

        // Double down
//         stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.SIX_OF_HEARTS));
//         stackedDeckForTesting.add(new Card(CardDefinition.FOUR_OF_DIAMONDS));
//         stackedDeckForTesting.add(new Card(CardDefinition.KING_OF_HEARTS));
//         stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_DIAMONDS));
//         stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_DIAMONDS));

        // Resplit aces
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_DIAMONDS));
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.KING_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_DIAMONDS));
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_DIAMONDS));

        // Resplit sixes
//         stackedDeckForTesting.add(new Card(CardDefinition.SIX_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_DIAMONDS));
//         stackedDeckForTesting.add(new Card(CardDefinition.SIX_OF_HEARTS));
//         stackedDeckForTesting.add(new Card(CardDefinition.KING_OF_HEARTS));
//         stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_HEARTS));
//         stackedDeckForTesting.add(new Card(CardDefinition.SIX_OF_DIAMONDS));
//         stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
//         stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));

        // Soft 18 vs 3t4
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_DIAMONDS));
        // stackedDeckForTesting.add(new Card(CardDefinition.SEVEN_OF_DIAMONDS));
        // stackedDeckForTesting.add(new Card(CardDefinition.KING_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_DIAMONDS));
        // stackedDeckForTesting.add(new Card(CardDefinition.FOUR_OF_HEARTS));

        // All tens...
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));

        // Player 18, vs dealer t2q
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TWO_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.QUEEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));

        // Player 6, vs dealer t2q
        // stackedDeckForTesting.add(new Card(CardDefinition.TWO_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.FOUR_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TWO_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.QUEEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));

        // Dealer blackjack:
        // stackedDeckForTesting.add(new Card(CardDefinition.FOUR_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.QUEEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));

        // Player blackjack:
        // stackedDeckForTesting.add(new Card(CardDefinition.TEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.FOUR_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.THREE_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.QUEEN_OF_SPADES));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.EIGHT_OF_CLUBS));

        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_HEARTS));
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_CLUBS));
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_DIAMONDS));
        // stackedDeckForTesting.add(new Card(CardDefinition.ACE_OF_SPADES));
    }
    public void stack(final String stackedDeck) {
        if (!Strings.isPopulated(stackedDeck)) {
            return;
        }
        stackedDeckForTesting.clear();
        StringReader sr = new StringReader(stackedDeck);
        BufferedReader br = new BufferedReader(sr);
        try {
            String s = br.readLine();
            while (s != null) {
                CardDefinition cd = CardDefinition.find(s);
                if (cd != null) {
                    stackedDeckForTesting.add(new Card(cd));
                }
                s = br.readLine();
            }
        } catch (IOException e) {
            Util.log(e);
        }
        shuffle();
    }
}
